package com.kstudio.videocapture.editvideo;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.kstudio.videocapture.gl.ImageGL2D;
import com.kstudio.videocapture.util.KLog;

public class KVideoEditViewSeekBar extends GLSurfaceView implements Renderer {
    private final KLog log = new KLog("KVideoEdit");

    private static final int INVALIDATE_NONE        = 0x0000;
    private static final int INVALIDATE_DO          = 0x0001;
    private static final int INVALIDATE_DOING       = 0x0002;
    private static final int INVALIDATE_INIT        = 0x0004;
    private static final int INVALIDATE_INIT_DONE   = 0x0008;

    private static final int INVALIDATE_TIME_FRONT  = 0x0010;
    private static final int INVALIDATE_TIME_REAR   = 0x0020;
    private static final int INVALIDATE_TIME_THUMB  = 0x0040;

    private KSeekViewListener mListener;

    private ImageGL2D mGlFrontTime;
    private ImageGL2D mGlRearTime;
    private ImageGL2D mGlThumbTime;

    private ImageGL2D mGlLeft;
    private ImageGL2D mGlRight;
    private ImageGL2D mGlCenter;
    private ImageGL2D mGlCenterPassed;
    private ImageGL2D mGlEdgeLeft;
    private ImageGL2D mGlEdgeRight;
    private ImageGL2D mGlThumb;

    private Bitmap mBmLeft;
    private Bitmap mBmRight;
    private Bitmap mBmCenter;
    private Bitmap mBmCenterPassed;
    private Bitmap mBmEdgeLeft;
    private Bitmap mBmEdgeRight;
    private Bitmap mBmThumb;

    private int mPaddingLeft;
    private int mPaddingRight;
    private int mPaddingTop;
    private int mPaddingBottom;
    private int mPaddingText;

    private int mPosEdgeL;
    private int mPosEdgeR;
    private int mPosCur;

    private int mTimeFront;
    private int mTimeRear;
    private int mTimeThumb;
    private int mTimeScale;

    private int mWidth;
    private int mHeight;

    private int mSbWidth;
    private int mTextSize;
    private int mDuration;

    private int invalidate;
    private int invalidateCnt;

    public interface KSeekViewListener {
        void onKSeekViewChangeTime(int time);
    }

    public KVideoEditViewSeekBar(Context context) {
        this(context, null);
    }

    public KVideoEditViewSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        log.i("SeekBar");

        mListener = null;

        mGlFrontTime = null;
        mGlRearTime = null;;
        mGlThumbTime = null;

        mGlLeft         = null;
        mGlRight        = null;
        mGlCenter       = null;
        mGlCenterPassed = null;
        mGlEdgeLeft     = null;
        mGlEdgeRight   = null;
        mGlThumb        = null;

        mBmLeft         = null;
        mBmRight        = null;
        mBmCenter       = null;
        mBmCenterPassed = null;
        mBmEdgeLeft     = null;
        mBmEdgeRight    = null;
        mBmThumb        = null;

        mPaddingLeft = 0;
        mPaddingRight = 0;
        mPaddingTop = 0;
        mPaddingBottom = 0;
        mPaddingText = 0;

        mPosCur = 0;
        mPosEdgeL = 0;
        mPosEdgeR = 0;

        mTimeFront = 0;
        mTimeRear = 0;
        mTimeThumb = 0;
        mTimeScale = 1;

        mSbWidth = 0;

        mTextSize = 10;
        mDuration = 0;

        invalidate = INVALIDATE_NONE;

        this.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        this.setRenderer(this);
        this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        this.setZOrderMediaOverlay(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);

        int height = mPaddingTop + mPaddingBottom + mPaddingText * 2;
        if(mBmLeft != null) height += mBmThumb.getHeight();
        height += mTextSize * 2;

        setMeasuredDimension(width, height);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        log.i("SeekBar : onSurfaceCreated");
        gl.glDisable(GL10.GL_DITHER);

        gl.glClearColor(0,0,0,0);

        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glClearDepthf(1.0f);
        gl.glEnable(GL10.GL_DEPTH_TEST);
        gl.glDepthFunc(GL10.GL_LEQUAL);

        gl.glEnable(GL10.GL_BLEND);
        //gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE);
        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
        gl.glEnable(GL10.GL_ALPHA_TEST);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        log.i("SeekBar : onSurfaceChanged");
        mWidth = width;
        mHeight = height;

        gl.glViewport(0, 0, width, height);

        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();

        //gl.glOrthof(0f, 1f, 0f, 1f, -1f, 1f);
        gl.glOrthof(0, width, 0, height, -1, 1);

        createElements(gl);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        draw(gl);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int posX = (int) event.getX();
        int posY = mHeight - (int) event.getY();

        switch(action) {
            case MotionEvent.ACTION_DOWN : {
                if(mGlThumb.checkIncludePosition(posX, posY)) {
                    return true;
                }
                break;
            }
            case MotionEvent.ACTION_MOVE : {
                moveThumb(posX - mGlLeft.getRight());
                changeTime();
                return true;
            }
            case MotionEvent.ACTION_UP :
            case MotionEvent.ACTION_CANCEL : {
                return true;
            }
        }
        return super.onTouchEvent(event);
    }

    public void setSeekViewListener(KSeekViewListener l) {
        mListener = l;
    }

    public synchronized void setDuration(int duration) {
        mDuration = duration;

        mTimeFront = 0;
        mTimeRear = mDuration;
        mTimeThumb = 0;

        invalidate = INVALIDATE_DO | INVALIDATE_INIT | INVALIDATE_TIME_FRONT | INVALIDATE_TIME_REAR | INVALIDATE_TIME_THUMB;
    }

    public void setTextSize(int size) { mTextSize = size; }

    /* Set Padding */
    public void setPaddingLeft(int p)          { mPaddingLeft = p; }
    public void setPaddingRight(int p)         { mPaddingRight = p; }
    public void setPaddingTop(int p)           { mPaddingTop = p; }
    public void setPaddingBottom(int p)        { mPaddingBottom = p; }
    public void setPaddingText(int p)          { mPaddingText = p; }

    /* Set Bitmap */
    public void setBmLeft(Bitmap b)         { mBmLeft = b; }
    public void setBmRight(Bitmap b)        { mBmRight = b; }
    public void setBmCenter(Bitmap b)       { mBmCenter = b; }
    public void setBmCenterPassed(Bitmap b) { mBmCenterPassed = b; }
    public void setBmEdgeLeft(Bitmap b)     { mBmEdgeLeft = b; }
    public void setBmEdgeRight(Bitmap b)    { mBmEdgeRight = b; }
    public void setBmThumb(Bitmap b)        { mBmThumb = b; }

    /* Get function */
    public int getThumbTime()           { return mTimeThumb; }
    public int getSeekBarWidth()        { return mSbWidth; }

    /* Seek Bar Control */
    public void setThumbTime(int time) {
        int pos = (int)(time * ((double) mSbWidth / (double) mDuration));
        mTimeThumb = time;

        if(mPosCur < pos) {
            moveThumb(pos);

        }
    }

    public void setThumbCompletion() {
        moveThumb(0);
        mTimeThumb = 0;
    }

    private synchronized void draw(GL10 gl) {
        if((invalidate & INVALIDATE_DO) == INVALIDATE_DO || (invalidate & INVALIDATE_DOING) == INVALIDATE_DOING) {
            if((invalidate & INVALIDATE_TIME_FRONT) == INVALIDATE_TIME_FRONT) {
                mGlFrontTime.loadTexture(gl, timeToText(mTimeFront), mTextSize);
                invalidate ^= INVALIDATE_TIME_FRONT;
            }

            if((invalidate & INVALIDATE_TIME_REAR) == INVALIDATE_TIME_REAR) {
                mGlRearTime.loadTexture(gl, timeToText(mTimeRear), mTextSize);
                invalidate ^= INVALIDATE_TIME_REAR;
            }

            if((invalidate & INVALIDATE_TIME_THUMB) == INVALIDATE_TIME_THUMB) {
                mGlThumbTime.loadTexture(gl, timeToText(mTimeThumb), mTextSize);
                invalidate ^= INVALIDATE_TIME_THUMB;
            }

            if((invalidate & INVALIDATE_INIT) == INVALIDATE_INIT) {
                layout(gl);
                invalidate ^= INVALIDATE_INIT;
                invalidate |= INVALIDATE_INIT_DONE;
            }

            if((invalidate & INVALIDATE_INIT_DONE) == INVALIDATE_INIT_DONE) {
                gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

                mGlFrontTime.draw(gl);
                mGlRearTime.draw(gl);
                mGlThumbTime.draw(gl);

                mGlLeft.draw(gl);
                mGlRight.draw(gl);
                mGlCenter.draw(gl);
                mGlCenterPassed.draw(gl);
                mGlEdgeLeft.draw(gl);
                mGlEdgeRight.draw(gl);
                mGlThumb.draw(gl);

                gl.glEnable(GL10.GL_BLEND);
                //gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE);
                gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
                gl.glEnable(GL10.GL_ALPHA_TEST);
            }
            //invalidate ^= INVALIDATE_DO;

            if((invalidate & INVALIDATE_DO) == INVALIDATE_DO) {
                invalidate ^= INVALIDATE_DO;
                invalidate |= INVALIDATE_DOING;
                invalidateCnt = 1;
            } else if((invalidate & INVALIDATE_DOING) == INVALIDATE_DOING) {
                if(invalidateCnt < 5)
                    invalidateCnt++;
                else
                    invalidate ^= INVALIDATE_DOING;
            }
        }
    }

    private synchronized void moveThumb(int x) {
        int l = 0;
        int r = 0;
        mPosCur = x;

        if(mPosCur < 0) mPosCur = 0;
        else if(mPosCur > mSbWidth) mPosCur = mSbWidth;

        l = mGlCenterPassed.getLeft();
        r = l + mPosCur;
        mGlCenterPassed.changeVertices(l, r, mGlCenterPassed.getBottom(), mGlCenterPassed.getTop());

        l = mGlCenterPassed.getRight();
        r = mGlRight.getLeft();
        mGlCenter.changeVertices(l, r, mGlCenter.getBottom(), mGlCenter.getTop());

        l = mGlLeft.getRight() + mPosCur - mGlThumb.getWidth() / 2;
        r = l + mGlThumb.getWidth();
        mGlThumb.changeVertices(l, r, mGlThumb.getBottom(), mGlThumb.getTop());

        l = mGlLeft.getRight() + mPosCur - mGlThumbTime.getWidth() / 2;
        r = l + mGlThumbTime.getWidth();
        mGlThumbTime.changeVertices(l, r, mGlThumbTime.getBottom(), mGlThumbTime.getTop());

        invalidate |= INVALIDATE_DO | INVALIDATE_TIME_THUMB;;
    }

    private void createElements(GL10 gl) {
        mGlFrontTime    = ImageGL2D.create();
        mGlRearTime     = ImageGL2D.create();
        mGlThumbTime    = ImageGL2D.create();

        mGlLeft         = ImageGL2D.createFromBmp(gl, mBmLeft);
        mGlRight        = ImageGL2D.createFromBmp(gl, mBmRight);
        mGlCenterPassed = ImageGL2D.createFromBmp(gl, mBmCenterPassed);
        mGlCenter       = ImageGL2D.createFromBmp(gl, mBmCenter);
        mGlEdgeLeft     = ImageGL2D.createFromBmp(gl, mBmEdgeLeft);
        mGlEdgeRight    = ImageGL2D.createFromBmp(gl, mBmEdgeRight);
        mGlThumb        = ImageGL2D.createFromBmp(gl, mBmThumb);

//        invalidate = INVALIDATE_DO | INVALIDATE_INIT | INVALIDATE_TIME_FRONT | INVALIDATE_TIME_REAR | INVALIDATE_TIME_THUMB;
    }

    private void layout(GL10 gl) {
        int lWithPadding = mPaddingLeft;
        int rWithPadding = mWidth - mPaddingRight;
        int bWithPadding = mPaddingBottom;
        int l = 0;
        int r = 0;
        int b = 0;
        int t = 0;

        b = bWithPadding;

        l = lWithPadding;
        r = l + mGlFrontTime.getWidth();
        t = b + mGlFrontTime.getHeight();
        mGlFrontTime.setLayout(l, r, b, t);

        l = rWithPadding - mGlRearTime.getWidth();
        r = l + mGlRearTime.getWidth();
        t = b + mGlRearTime.getHeight();
        mGlRearTime.setLayout(l, r, b, t);

        b += mPaddingText + mGlRearTime.getHeight();

        l = lWithPadding + mGlFrontTime.getWidth() / 2 - mGlLeft.getWidth();
        r = l + mGlLeft.getWidth();
        t = b + mGlLeft.getHeight();
        mGlLeft.setLayout(l, r, b, t);

        l = rWithPadding - mGlRearTime.getWidth() / 2;
        r = l + mGlRight.getWidth();
        t = b + mGlRight.getHeight();
        mGlRight.setLayout(l, r, b, t);

        l = mGlLeft.getRight();
        r = l + mPosCur;
        t = b + mGlCenterPassed.getHeight();
        mGlCenterPassed.setLayout(l, r, b, t);

        l = mGlCenterPassed.getRight();
        r = mGlRight.getLeft();
        t = b + mGlCenter.getHeight();
        mGlCenter.setLayout(l, r, b, t);

        l = mGlLeft.getRight() + mPosCur - mGlThumb.getWidth() / 2;
        r = l + mGlThumb.getWidth();
        t = b + mGlThumb.getHeight();
        mGlThumb.setLayout(l, r, b, t);

        l = mGlLeft.getRight();
        b += (mGlThumb.getHeight() - mGlEdgeLeft.getHeight()) / 2;
        r = l + mGlEdgeLeft.getWidth();
        t = b + mGlEdgeLeft.getHeight();
        mGlEdgeLeft.setLayout(l, r, b, t);

        l = mGlRight.getLeft() - mGlEdgeRight.getWidth();
        r = l + mGlEdgeRight.getWidth();
        t = b + mGlEdgeRight.getHeight();
        mGlEdgeRight.setLayout(l, r, b, t);

        l = mGlLeft.getRight() + mPosCur - mGlThumbTime.getWidth() / 2;
        r = l + mGlThumbTime.getWidth();
        b = mGlThumb.getTop() + mPaddingText;
        t = b + mGlThumbTime.getHeight();
        mGlThumbTime.setLayout(l, r, b, t);

        mPosEdgeL = mGlLeft.getRight();
        mPosEdgeR = mGlRight.getLeft();
        mSbWidth = mGlRight.getLeft() - mGlLeft.getRight();
    }

    private void changeTime() {
        mTimeThumb = (int)(mPosCur * ((double) mDuration / (double) mSbWidth));

        if(mListener != null) mListener.onKSeekViewChangeTime(mTimeThumb);
    }

    private String timeToText(int time) {
        int sec  = time / 1000;
        int min  = (sec / 60) % 60;
        int hour = sec / 3600;
        sec      = sec % 60;

        if(hour > 0) {
            return String.format("%02d:%02d:%02d", hour, min, sec);
        } else {
            return String.format("%02d:%02d", min, sec);
        }
    }
}
